#include "CSceneLoader.h"
#include <tinyxml.h>
#include "CSimpleScene.h"
#include "CRayTracer.h"
#include <sstream>
using std::stringstream;

#include <iostream>
using std::cout;
using std::endl;

//lights
#include "CPointLight.h"
#include "CDirectionalLight.h"
#include "CSpotLight.h"

//primitives
#include "CPrimPlan.h"
#include "CPrimSphere.h"
#include "CPrimCylinder.h"
#include "CPrimCone.h"
#include "CPrimTore.h"
#include "CPrimTriangle.h"
#include "CPrimBox.h"
#include "CPrimCSG.h"

#include "CMatrix.h"

#include "CProcTextureChecker.h"
#include "CProcTextureWood.h"
#include "CProcTextureMarble.h"
#include "CProcTextureThreshold.h"
#include "CProcTextureBump.h"

#include "CNodeCSG.h"
#include "booleanType.h"

#include "CMaterial.h"

CSceneLoader::CSceneLoader(){}

bool CSceneLoader::load(const string& filename)
{
	//open the xml document
	TiXmlDocument doc;
	if(!doc.LoadFile(filename.c_str()))
		return false;

	m_filename = filename;

	//check if the root is valid
	TiXmlElement* root = doc.RootElement();
	string nodeName = root->Value();
	if(nodeName.compare("Raytracer")!=0)
		return false;

	//get the first child
	TiXmlElement* currentNode = root->FirstChildElement();

	//go throught the xml
	while(currentNode != 0)
	{
		nodeName = currentNode->Value();

		if(nodeName.compare("Scene") == 0)
			loadScene(currentNode);
		else if (nodeName.compare("Configuration") == 0)
			loadConfiguration(currentNode);

		currentNode = currentNode->NextSiblingElement();
	}

	return true;
}


void CSceneLoader::loadConfiguration(TiXmlElement* config)const
{
	//get the first child
	TiXmlElement* currentNode = config->FirstChildElement();

	while(currentNode != 0)
	{
		string name = currentNode->Value();

		if(name.compare("RatioAndFoV") == 0)
		{
			CVector3f p;
			getVector3(currentNode, p);

			RAYTRACER.setScreen(p.x, p.y, p.z);
		}
		else if (name.compare("Resolution") == 0)
		{
			int w, h;
			stringstream ss;
			ss<<currentNode->GetText();
			ss>>w;
			ss>>h;
			
			RAYTRACER.setResolution(w, h);
		}
		else if(name.compare("OversamplingLevel") == 0)
		{
			int level = 0;
			stringstream ss;
			ss<<currentNode->GetText();
			ss>>level;

			switch(level)
			{
			case 0:
				RAYTRACER.setOverSampling(CRayTracer::NO_OVERSAMPLING);
				break;
			case 1:
				RAYTRACER.setOverSampling(CRayTracer::LVL1_OVERSAMPLING);
				break;
			case 2:
				RAYTRACER.setOverSampling(CRayTracer::LVL2_OVERSAMPLING);
				break;

			default:
				RAYTRACER.setOverSampling(CRayTracer::NO_OVERSAMPLING);
			}

		}

		//get next node
		currentNode = currentNode->NextSiblingElement();
	}
}

void CSceneLoader::loadScene(TiXmlElement* scene)const
{
	//get the first child
	TiXmlElement* currentNode = scene->FirstChildElement();

	//go throught the xml
	while(currentNode != 0)
	{
		string nodeName = currentNode->Value();

		if(nodeName.compare("Lights") == 0)
			loadLights(currentNode);
		else if (nodeName.compare("Materials") == 0)
			loadMaterials(currentNode);
		else if(nodeName.compare("Objects") == 0)
			loadObjects(currentNode);

		currentNode = currentNode->NextSiblingElement();
	}
}

void CSceneLoader::loadLights(TiXmlElement* light)const
{
	//storage variables
	CVector3f position, direction, attenuation;
	CColor color;
	float cutOff = 0;
	float beam = 0;

	//get the first light
	TiXmlElement* currentLight = light->FirstChildElement();

	//for every light
	while(currentLight != 0)
	{
		//get the light name
		string nodeName = currentLight->Value();

		//if point light
		if(nodeName.compare("PointLight") == 0)
		{
			TiXmlElement* parameter = currentLight->FirstChildElement();
			
			while(parameter != 0)
			{
				string paramName = parameter->Value();
				if(paramName.compare("Position") == 0)
					getVector3(parameter, position);
				else if (paramName.compare("Color") == 0)
					getVector3(parameter, color);
				else if (paramName.compare("Attenuation") == 0)
					getVector3(parameter, attenuation);

				//get next parameter
				parameter = parameter->NextSiblingElement();
			}

			//add light
			SCENE.addLight(new CPointLight(position, color, attenuation));
		}
		//if directional
		else if (nodeName.compare("DirectionalLight") == 0)
		{
			TiXmlElement* parameter = currentLight->FirstChildElement();
			
			while(parameter != 0)
			{
				string paramName = parameter->Value();
				if(paramName.compare("Direction") == 0)//store the idrection on the position
					getVector3(parameter, direction);
				else if (paramName.compare("Color") == 0)
					getVector3(parameter, color);
				//get next parameter
				parameter = parameter->NextSiblingElement();
			}

			//add light
			SCENE.addLight(new CDirectionalLight(color, direction));
		}
		//if spot
		else if (nodeName.compare("SpotLight") == 0)
		{
			TiXmlElement* parameter = currentLight->FirstChildElement();
			
			while(parameter != 0)
			{
				string paramName = parameter->Value();
				if(paramName.compare("Position") == 0)//store the idrection on the position
					getVector3(parameter, position);
				else if (paramName.compare("Color") == 0)
					getVector3(parameter, color);
				else if(paramName.compare("Direction") == 0)
					getVector3(parameter, direction);
				else if(paramName.compare("Attenuation") == 0)
					getVector3(parameter, attenuation);
				else if(paramName.compare("CutOff") == 0)
					cutOff = getFloat(parameter);
				else if(paramName.compare("Beam") == 0)
					beam = getFloat(parameter);
				//get next parameter
				parameter = parameter->NextSiblingElement();
			}

			//add light
			SCENE.addLight(new CSpotLight(color, position, direction, cutOff, beam, attenuation));
		}

		//get the next light
		currentLight = currentLight->NextSiblingElement();
	}
}

void CSceneLoader::loadMaterials(TiXmlElement* material)const
{
	//get the first material
	TiXmlElement* currentMaterial = material->FirstChildElement();

	//for every material
	while(currentMaterial != 0)
	{
		//get the material name
		string matName = currentMaterial->Attribute("name");
		if(SCENE.getMaterial(matName) != 0)
		{
			cout<<"ERROR MATERIAL : "<<matName<<endl;
			currentMaterial = currentMaterial->NextSiblingElement();
			continue;
		}
		
		//create the material
		CMaterial* material = new CMaterial();

		//get the parameters
		TiXmlElement* parameter = currentMaterial->FirstChildElement();
		while(parameter != 0)
		{
			CColor color;
			string parameterName = parameter->Value();
			if(parameterName.compare("Diffuse") == 0)
			{
				CColor d;
				getVector3(parameter, d);
				material->setDiffuse(d);
			}
			//else if(parameterName.compare("Ambient") == 0)
			//	getVector3(parameter, material->m_ambient);
			/*else if(parameterName.compare("Specular") == 0)
				getVector3(parameter, material->m_specular);*/
			else if(parameterName.compare("Reflect") == 0)
				getVector3(parameter, material->m_reflect);
			else if(parameterName.compare("Shininess") == 0)
				material->m_shininess = getFloat(parameter);
			else if(parameterName.compare("Refraction") == 0)
				material->m_refractionIndex = getFloat(parameter);
			else if(parameterName.compare("Transparancy") == 0)
				material->m_transparancyCoef = getFloat(parameter);
			else if(parameterName.compare("ProceduralTexture") == 0)
			{
				string procTextName = parameter->Attribute("type");
				if(procTextName.compare("Checker") == 0)
					loadProcTextureChecker(parameter, material);
				else if(procTextName.compare("Wood") == 0)
					loadProcTextureWood(parameter, material);
				else if(procTextName.compare("Marble") == 0)
					loadProcTextureMarble(parameter, material);
				else if(procTextName.compare("Threshold") == 0)
					loadProcTextureThreshold(parameter, material);
				else if(procTextName.compare("Bump") == 0)
					loadProcTextureBump(parameter, material);
			}

			parameter = parameter->NextSiblingElement();
		}
		
		//add the material
		SCENE.addMaterial(material, matName);

		//get the next material
		currentMaterial = currentMaterial->NextSiblingElement();
	}
}

void CSceneLoader::loadObjects(TiXmlElement* object)const
{
	//get the first object
	TiXmlElement* currentObject = object->FirstChildElement();

	//for every object
	while(currentObject != 0)
	{
		//get the object type
		string objectType = currentObject->Attribute("type");

		//store the objects
		IPrimitive* object = 0;

		if(objectType.compare("Plan") == 0)
			object = loadGeometryPlan(currentObject);
		else if(objectType.compare("Sphere") == 0)
			object = loadGeometrySphere(currentObject);
		else if(objectType.compare("Cylinder") == 0)
			object = loadGeometryCylinder(currentObject);
		else if(objectType.compare("Cone") == 0)
			object = loadGeometryCone(currentObject);
		else if(objectType.compare("Torus") == 0)
			object = loadGeometryTorus(currentObject);
		else if(objectType.compare("Camera") == 0)
			loadGeometryCamera(currentObject);
		else if(objectType.compare("Triangle") == 0)
			object = loadGeometryTriangle(currentObject);
		else if(objectType.compare("Box") == 0)
			object = loadGeometryBox(currentObject);
		else if(objectType.compare("CSG") == 0)
			object = loadGeometryCSG(currentObject);
		else if(objectType.compare("FromFile") == 0)
			object = loadGeometryFromFile(currentObject);
		
		//get the next object
		currentObject = currentObject->NextSiblingElement();

		//add the object to the scene
		if(object != 0)
			SCENE.addPrimitive(object);
		
	}
}

IPrimitive* CSceneLoader::loadModelFile(const string& filename)const
{
	//open the xml document
	TiXmlDocument doc;
	if(!doc.LoadFile(filename.c_str()))
		return false;

	//check if the root is valid
	TiXmlElement* root = doc.RootElement();
	string nodeName = root->Value();
	if(nodeName.compare("Model")!=0)
		return false;

	//get the first child
	TiXmlElement* currentNode = root->FirstChildElement();
	
	IPrimitive* primitive = 0;

	//go throught the xml
	while(currentNode != 0)
	{
		nodeName = currentNode->Value();

		if(nodeName.compare("Materials") == 0)
			loadMaterials(currentNode);
		else if (nodeName.compare("Objects") == 0)
		{
			TiXmlElement* child = currentNode->FirstChildElement();

			//get the type of primitive
			string objectType = child->Attribute("type");

			//load the primitive
			if(objectType.compare("Plan") == 0)
				primitive = loadGeometryPlan(child);
			else if(objectType.compare("Sphere") == 0)
				primitive = loadGeometrySphere(child);
			else if(objectType.compare("Cylinder") == 0)
				primitive = loadGeometryCylinder(child);
			else if(objectType.compare("Cone") == 0)
				primitive = loadGeometryCone(child);
			else if(objectType.compare("Torus") == 0)
				primitive = loadGeometryTorus(child);
			else if(objectType.compare("Triangle") == 0)
				primitive = loadGeometryTriangle(child);
			else if(objectType.compare("Box") == 0)
				primitive = loadGeometryBox(child);
			else if(objectType.compare("CSG") == 0)
				primitive = loadGeometryCSG(child);
		}

		currentNode = currentNode->NextSiblingElement();
	}

	return primitive;
}

void CSceneLoader::loadGeometryCamera(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//create the camera vectors
	CVector3f eye, at, up;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		if(paramName.compare("Eye") == 0)
			getVector3(parameter, eye);
		else if(paramName.compare("At") == 0)
			getVector3(parameter, at);
		else if(paramName.compare("Up") == 0)
			getVector3(parameter, up);
		
		//get next parameter
		parameter = parameter->NextSiblingElement();
	}

	//set camera
	RAYTRACER.setViewer(eye, at, up);
}

IPrimitive* CSceneLoader::loadGeometryPlan(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//creat the three points representing the plan
	CVector3f P1, P2, P3;

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();
		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Model") == 0)
		{
			//get plan model
			string model = parameter->GetText();
			
			if(model.compare("xOy") == 0)
			{
				P1 = CVector3f(0, 0, 0);
				P2 = CVector3f(1, 0, 0);
				P3 = CVector3f(1, 1, 0);
			}
			else if (model.compare("xOz") == 0)
			{
				P1 = CVector3f(0, 0, 0);
				P2 = CVector3f(1, 0, 0);
				P3 = CVector3f(1, 0, -1);
			}
			else if(model.compare("yOz") == 0)
			{
				P1 = CVector3f(0, 0, 0);
				P2 = CVector3f(0, 1, 0);
				P3 = CVector3f(0, 1, 1);
			}

		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the plan
	CPrimPlan* plan = new CPrimPlan(P1, P2, P3);
	plan->setMaterial(material);
	plan->setMatrices(TMatrix, RMatrix, S);
	return plan;
	//SCENE.addPrimitive(plan);
}

IPrimitive* CSceneLoader::loadGeometrySphere(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//creat the three points representing the sphere
	CVector3f center;
	float radius = 0;

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Radius") == 0)
		{
			radius = getFloat(parameter);
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the sphere
	CPrimSphere* sphere = new CPrimSphere(radius);
	sphere->setMaterial(material);
	sphere->setMatrices(TMatrix, RMatrix, S);
	return sphere;
	//SCENE.addPrimitive(sphere);
}

IPrimitive* CSceneLoader::loadGeometryCylinder(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//cradius and height
	float height = 0;
	float radius = 0;

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Height") == 0)
		{
			height = getFloat(parameter);
		}
		else if(paramName.compare("Radius") == 0)
		{
			radius = getFloat(parameter);
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the cylinder
	CPrimCylinder* cylinder = new CPrimCylinder(radius, height);
	cylinder->setMaterial(material);
	cylinder->setMatrices(TMatrix, RMatrix, S);
	return cylinder;
	//SCENE.addPrimitive(cylinder);
}

IPrimitive* CSceneLoader::loadGeometryCone(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//radius and height
	float height = 0;
	float radius = 0;

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Height") == 0)
		{
			height = getFloat(parameter);
		}
		else if(paramName.compare("Radius") == 0)
		{
			radius = getFloat(parameter);
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the cylinder
	CPrimCone* cone = new CPrimCone(radius, height);
	cone->setMaterial(material);
	cone->setMatrices(TMatrix, RMatrix, S);
	return cone;
	//SCENE.addPrimitive(cone);
}

IPrimitive* CSceneLoader::loadGeometryTorus(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//radius and height
	float br = 0;
	float sr = 0;

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("BigRadius") == 0)
		{
			br = getFloat(parameter);
		}
		else if(paramName.compare("SmallRadius") == 0)
		{
			sr = getFloat(parameter);
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the torus
	CPrimTore* tore = new CPrimTore(br, sr);
	tore->setMaterial(material);
	tore->setMatrices(TMatrix, RMatrix, S);
	return tore;
	//SCENE.addPrimitive(tore);
}

IPrimitive* CSceneLoader::loadGeometryTriangle(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//store the 3 points
	CVector3f P[3];

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Point") == 0)
		{
			//get the text in a stringstream
			stringstream ss;
			ss<<parameter->GetText();

			//create the point
			ss>>P[0].x; ss>>P[0].y; ss>>P[0].z;
			ss>>P[1].x; ss>>P[1].y; ss>>P[1].z;
			ss>>P[2].x; ss>>P[2].y; ss>>P[2].z;
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the triangle
	CPrimTriangle* triangle = new CPrimTriangle(P);
	triangle->setMaterial(material);
	triangle->setMatrices(TMatrix, RMatrix, S);
	return triangle;
	//SCENE.addPrimitive(triangle);
}

IPrimitive* CSceneLoader::loadGeometryBox(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//store the box dimension
	CVector3f dimension;

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//pointer to the material
	CMaterial* material = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Dimension") == 0)
		{
			getVector3(parameter, dimension);
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the box
	CPrimBox* box = new CPrimBox(dimension.x, dimension.y, dimension.z);
	box->setMaterial(material);
	box->setMatrices(TMatrix, RMatrix, S);
	return box;
	//SCENE.addPrimitive(box);
}

IPrimitive* CSceneLoader::loadGeometryCSG(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix TMatrix, RMatrix, S;
	TMatrix.identity();
	RMatrix.identity();
	S.identity();

	//pointer to the material
	CMaterial* material = 0;

	//root
	CNodeCSG* root = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			RMatrix = RMatrix * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			TMatrix = TMatrix * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Material") == 0)
		{
			string nameMaterial = parameter->GetText();
			material = SCENE.getMaterial(nameMaterial);
		}
		else if(paramName.compare("Node") == 0)
		{
			root = loadNodeCSG(parameter);
		}

		parameter = parameter->NextSiblingElement();
	}

	//create the box
	CPrimCSG* csg = new CPrimCSG(root);
	csg->setMaterial(material);
	csg->setMatrices(TMatrix, RMatrix, S);
	return csg;
	//SCENE.addPrimitive(csg);
}

CNodeCSG* CSceneLoader::loadNodeCSG(TiXmlElement* element)const
{
	//temp variables
	CNodeCSG* child1 = 0;
	CNodeCSG* child2 = 0;
	IPrimitive* primitive = 0;

	//get the type of node
	string nodeType = element->Attribute("type");
	eBoolType eNodeType = eBoolNone;
	if(nodeType.compare("Difference") == 0)
		eNodeType = eBoolDifference;
	else if(nodeType.compare("Intersection") == 0)
		eNodeType = eBoolIntersection;
	else if(nodeType.compare("Union") == 0)
		eNodeType = eBoolUnion;

	//get the fist child
	TiXmlElement* child = element->FirstChildElement();

	//go throught the children
	while(child != 0)
	{
		string nodeName = child->Value();

		//node
		if(nodeName.compare("Node") == 0)
		{
			if(child1 == 0)
				child1 = loadNodeCSG(child);
			else
				child2 = loadNodeCSG(child);
		}
		else if (nodeName.compare("Primitive") == 0)
		{
			//get the type of primitive
			string objectType = child->Attribute("type");

			//load the primitive
			if(objectType.compare("Plan") == 0)
				primitive = loadGeometryPlan(child);
			else if(objectType.compare("Sphere") == 0)
				primitive = loadGeometrySphere(child);
			else if(objectType.compare("Cylinder") == 0)
				primitive = loadGeometryCylinder(child);
			else if(objectType.compare("Cone") == 0)
				primitive = loadGeometryCone(child);
			else if(objectType.compare("Torus") == 0)
				primitive = loadGeometryTorus(child);
			else if(objectType.compare("Triangle") == 0)
				primitive = loadGeometryTriangle(child);
			else if(objectType.compare("Box") == 0)
				primitive = loadGeometryBox(child);
		}

		//get the next child
		child = child->NextSiblingElement();
	}

	//create the node
	CNodeCSG* node = new CNodeCSG(primitive, eNodeType, child1, child2);
	return node;
	

}

IPrimitive* CSceneLoader::loadGeometryFromFile(TiXmlElement* element)const
{
	//get the first parameter
	TiXmlElement* parameter = element->FirstChildElement();

	//set matrices
	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	//primitive
	IPrimitive* prim = 0;

	//for every parameter
	while(parameter != 0)
	{
		//get the param type
		string paramName = parameter->Value();

		CMatrix tempMatrix;
		tempMatrix.identity();

		if(paramName.compare("Rotate") == 0)
		{
			loadTransformRotation(parameter, tempMatrix);
			R = R * tempMatrix;
		}
		else if(paramName.compare("Translate") == 0)
		{
			loadTransformTranslate(parameter, tempMatrix);
			T = T * tempMatrix;
		}
		else if(paramName.compare("Scale") == 0)
		{
			loadTransformScale(parameter, tempMatrix);
			S = S * tempMatrix;
		}
		else if(paramName.compare("Source") == 0)
		{
			string sourceFile = parameter->GetText();
			prim = loadModelFile(sourceFile);
			if(!prim)
			{
				cout<<"Error during model loading : "<<sourceFile<<endl;
				system("pause");
				return false;
			}
		}

		parameter = parameter->NextSiblingElement();
	}

	//return the primitive
	prim->setMatrices(T, R, S);
	return prim;

}

void CSceneLoader::loadTransformRotation(TiXmlElement* element, CMatrix& out)const
{
	//get the axis
	string axis = element->Attribute("axis");
	
	//get the angle
	float theta = getFloat(element);

	//create the rotation matrix
	if(axis.compare("X")==0)
		out.createRotationX(theta);
	else if(axis.compare("Y")==0)
		out.createRotationY(theta);
	else if(axis.compare("Z")==0)
		out.createRotationZ(theta);
}

void CSceneLoader::loadTransformTranslate(TiXmlElement* element, CMatrix& out)const
{
	CVector3f translationV;
	getVector3(element, translationV);
	out.createTranslation(translationV.x, translationV.y, translationV.z);
}

void CSceneLoader::loadTransformScale(TiXmlElement* element, CMatrix& out)const
{
	string type = element->Attribute("type");
	if(type.compare("uniform") == 0)
	{
		float s = getFloat(element);
		out.createScale(s);
	}
	else
	{
		CVector3f s;
		getVector3(element, s);
		out.createScale(s);
	}
}

void CSceneLoader::loadProcTextureChecker(TiXmlElement* element, CMaterial* material)const
{
	CColor color[2];
	float length;
	CVector3f map;

	//transformation matrices
	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	TiXmlElement* parameter = element->FirstChildElement();
	while(parameter != 0)
	{
		CMatrix temp;
		string paramName = parameter->Value();

		if(paramName.compare("Color1") == 0)
			getVector3(parameter, color[0]);
		else if(paramName.compare("Color2") == 0)
			getVector3(parameter, color[1]);
		else if(paramName.compare("Length") == 0)
			length = getFloat(parameter);
		else if(paramName.compare("Map") == 0)
			getVector3(parameter, map);
		else if(paramName.compare("Translate")==0)
		{
			loadTransformTranslate(parameter, temp);
			T = T * temp;
		}
		else if(paramName.compare("Rotate")==0)
		{
			loadTransformRotation(parameter, temp);
			R = R * temp;
		}
		else if(paramName.compare("Scale")==0)
		{
			loadTransformScale(parameter, temp);
			S = S * temp;
		}

		parameter = parameter->NextSiblingElement();
	}

	CProcTextureChecker* texture = new CProcTextureChecker(color, length, map);
	texture->setMatrices(T, R, S);
	//material->setProcTexture(texture);
	material->setAmbient(texture);
	material->setDiffuse(texture);
	SCENE.addTexture(texture);
}

void CSceneLoader::loadProcTextureWood(TiXmlElement* element, CMaterial* material)const
{
	float persistance = 0;
	float treshold = 0;
	int octave = 0;

	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	TiXmlElement* parameter = element->FirstChildElement();
	while(parameter != 0)
	{
		CMatrix temp;
		string paramName = parameter->Value();

		if(paramName.compare("Persistance") == 0)
			persistance = getFloat(parameter);
		else if(paramName.compare("Threshold") == 0)
			treshold = getFloat(parameter);
		else if(paramName.compare("Octave") == 0)
			octave = (int)getFloat(parameter);
		else if(paramName.compare("Translate")==0)
		{
			loadTransformTranslate(parameter, temp);
			T = T * temp;
		}
		else if(paramName.compare("Rotate")==0)
		{
			loadTransformRotation(parameter, temp);
			R = R * temp;
		}
		else if(paramName.compare("Scale")==0)
		{
			loadTransformScale(parameter, temp);
			S = S * temp;
		}

		parameter = parameter->NextSiblingElement();
	}

	CProcTextureWood* texture = new CProcTextureWood(persistance, octave, treshold);
	texture->setMatrices(T, R, S);
	//material->setProcTexture(texture);
	material->setAmbient(texture);
	material->setDiffuse(texture);
	SCENE.addTexture(texture);
}

void CSceneLoader::loadProcTextureMarble(TiXmlElement* element, CMaterial* material)const
{
	float persistance = 0;
	int octave = 0;

	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	TiXmlElement* parameter = element->FirstChildElement();
	while(parameter != 0)
	{
		CMatrix temp;
		string paramName = parameter->Value();

		if(paramName.compare("Persistance") == 0)
			persistance = getFloat(parameter);
		else if(paramName.compare("Octave") == 0)
			octave = (int)getFloat(parameter);
		else if(paramName.compare("Translate")==0)
		{
			loadTransformTranslate(parameter, temp);
			T = T * temp;
		}
		else if(paramName.compare("Rotate")==0)
		{
			loadTransformRotation(parameter, temp);
			R = R * temp;
		}
		else if(paramName.compare("Scale")==0)
		{
			loadTransformScale(parameter, temp);
			S = S * temp;
		}

		parameter = parameter->NextSiblingElement();
	}

	CProcTextureMarble* texture = new CProcTextureMarble(persistance, octave);
	texture->setMatrices(T, R, S);
	//material->setProcTexture(texture);
	material->setAmbient(texture);
	material->setDiffuse(texture);
	SCENE.addTexture(texture);
}

void CSceneLoader::loadProcTextureThreshold(TiXmlElement* element, CMaterial* material)const
{
	float threshold;
	CColor c;

	stringstream ss;

	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	CProcTextureThreshold* texture = new CProcTextureThreshold();

	TiXmlElement* parameter = element->FirstChildElement();
	while(parameter != 0)
	{
		CMatrix temp;
		string paramName = parameter->Value();

		if(paramName.compare("Persistance") == 0)
			texture->setPersistance(getFloat(parameter));
		else if(paramName.compare("Octave") == 0)
			texture->setOctave( (int)getFloat(parameter));
		else if(paramName.compare("Intensity") == 0)
			texture->setIntensity( getFloat(parameter));
		else if(paramName.compare("Threshold") == 0)
		{
			ss.flush();
			ss.clear();
			ss << parameter->Attribute("value");
			ss >> threshold;
			getVector3(parameter, c);
			texture->addThreshold(threshold, c);
		}
		else if(paramName.compare("Translate")==0)
		{
			loadTransformTranslate(parameter, temp);
			T = T * temp;
		}
		else if(paramName.compare("Rotate")==0)
		{
			loadTransformRotation(parameter, temp);
			R = R * temp;
		}
		else if(paramName.compare("Scale")==0)
		{
			loadTransformScale(parameter, temp);
			S = S * temp;
		}
			
		parameter = parameter->NextSiblingElement();
	}

	texture->setMatrices(T, R, S);
	//material->setProcTexture(texture);
	material->setAmbient(texture);
	material->setDiffuse(texture);
	SCENE.addTexture(texture);
}

void CSceneLoader::loadProcTextureBump(TiXmlElement* element, CMaterial* material)const
{
	float persistance = 0;
	float intensity = 0;
	int octave = 0;

	CMatrix T, R, S;
	T.identity(); R.identity(); S.identity();

	TiXmlElement* parameter = element->FirstChildElement();
	while(parameter != 0)
	{
		CMatrix temp;

		string paramName = parameter->Value();

		if(paramName.compare("Persistance") == 0)
			persistance = getFloat(parameter);
		else if(paramName.compare("Octave") == 0)
			octave = (int)getFloat(parameter);
		else if(paramName.compare("Intensity") == 0)
			intensity = getFloat(parameter);
		else if(paramName.compare("Translate")==0)
		{
			loadTransformTranslate(parameter, temp);
			T = T * temp;
		}
		else if(paramName.compare("Rotate")==0)
		{
			loadTransformRotation(parameter, temp);
			R = R * temp;
		}
		else if(paramName.compare("Scale")==0)
		{
			loadTransformScale(parameter, temp);
			S = S * temp;
		}

		parameter = parameter->NextSiblingElement();
	}

	
	CProcTextureBump* texture = new CProcTextureBump(persistance, octave, intensity);
	texture->setMatrices(T, R, S);
	material->setBumpMap(texture);
	SCENE.addTexture(texture);
}

void CSceneLoader::getVector3(TiXmlElement* position, CVector3f& vector3)const
{
	stringstream ss;
	ss<<position->GetText();
	ss>>vector3.x;
	ss>>vector3.y;
	ss>>vector3.z;
}

float CSceneLoader::getFloat(TiXmlElement* element)const
{
	stringstream ss;
	ss<<element->GetText();
	float f;
	ss>>f;
	return f;
}